<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // ===============================================================================
    // 默认值
    // function fn(a, b) {
    //     a = a || '你好'
    //     b = b || '你好宝贝'
    //    return console.log(a, b);
    // }
    // fn('你好亲爱的')

    // --------------------------------------------------------------------------------
    // 有默认值的参数一定是在后面的
    // function fn(a = '你好', b = '你好宝贝') {return console.log(a,b);
    //  }
    // fn('你好亲爱的')


    // --------------------------------------------------------------------------------
    // 函数参数默认值
    // 1.
    // function fn({ x = 'jay', y = 20 } = {}) {
    //     return console.log(x, y);
    // }
    // fn()// jay   20
    // fn({x:'JoLin'})//JoLin  20
    // fn({})//jay   20
    // fn({z:'JoLin'})//jay   20

    // --------------------------------------------------------------------------------
    // 2.
    // function fn({ x, y} = {x:'jay',y:'20'}) {
    //     return console.log(x, y);
    // }
    // fn()//jay  20
    // fn({x:'JoLin'})//JoLin  undefined
    // fn({})//undefined   undefined
    // fn({z:'JoLin'})//undefined  undefined
    // ===============================================================================
    // 函数参数的作用域
    // 函数参数如果有默认值的话会形成一个独立的作用域（和函数作用域没有影响），当初始化完成后会自动销毁
    // --------------------------------------------------------------------------------
    // 1.
    // var a = 1;
    // function fn(a, b = a) {
    //     console.log(b);
    // }
    // fn(2);//2
    // fn()//undefined

    // --------------------------------------------------------------------------------
    // 2.
    // let y = 5;
    // function fn(a=y){
    //     let y =10;
    //     console.log(a);
    // }
    // // 因为没有传参，会触发默认值，因为没有y会向上去找，找到y=5，所以打印为5
    // fn()//5

    // --------------------------------------------------------------------------------
    // 3.
    // function fn(x = x) {
    //     let x = 2
    //     console.log(x);
    // }
    // fn()//报错


    // ===============================================================================
    // rest函数剩余参数 ‘...’
    // arguments不是数组，不能使用数组的方法，非常不灵活
    // rest参数：是数组，可以使用数组的方法，非常方便

    // --------------------------------------------------------------------------------
    // 1.arguments
    // function fn() {
    //     // 转换为数组
    //     Array.prototype.slice.call(arguments);
    //     console.log(arguments);
    // }
    // fn(1, 2, 3, 4, 5, 6);

    // --------------------------------------------------------------------------------
    // 2.rest
    // function fn(...a) {
    //     console.log(a);
    // }
    // fn(1, 2, 3, 4, 5, 6)

    // --------------------------------------------------------------------------------
    // 函数本身也是对象，有length属性，该属性代表函数参数个数
    // var fn = function (a) { }
    // var fn1 = function (...b) { }
    // var fn2 = function (a, ...b) { }
    // console.log(fn.length);//1
    // // 不包含rest参数
    // console.log(fn1.length);//0
    // console.log(fn2.length);//1


    // ===============================================================================
    // 箭头函数
    // 很大程度上缓解了this的指向问题

    // 1.基本用法    (没有return，他也会自动返回)
    // var a = () => 'c'
    // console.log(a());//c

    // 2.有一个参数时
    // var fn = (name) => `你好${name}`
    // console.log(fn('jay'));

    // 3.有两个参数时
    // var fn = (name, age) => `你好${name},你今年${age}了吗？`
    // console.log(fn('jay', 18));

    // 4.进行处理
    // var fn = (a) => (a = + 1, a)
    // console.log(fn(1));//2
    // 相当于：
    // function fn(a) {
    //     a += 1
    //     return a;
    // }
    // console.log(fn(1));//2


    // 5.参数如果是对象(要给对象加一个括号)
    // var fn =() =>({name:'jay',age:'18'})
    // console.log(fn());




    // --------------------------------------------------------------------------------
    // 面试题：箭头函数和普通函数的区别
    // 1.箭头函数没有自己的this，箭头函数内部的this是继承父级作用域的，普通函数是有自己的this的
    // 2.箭头函数没有arguments，普通函数有arguments
    // 3.箭头函数不能作为构造函数的，不可以使用new，普通函数可以

    // --------------------------------------------------------------------------------
    // 注意事项：
    // 如果对象里的某个方法内部使用到了this，此时不建议使用箭头函数
    // var cat = {
    //     lives: 9,
    //     // this指向的是window
    //     jumps: () => {
    //         this.lives--
    //     }
    // }

    // 推荐下面的方法
    // var cat = {
    //     lives: 9,
    //     jumps() {
    //         this.lives--
    //     },
    //     // 相当于下面这个的写法
    //     //  jumps: function (a, b) {
    //     //     this.lives--
    //     // }
    // }



    // ===============================================================================
    // 数组
    // 扩展运算符...
    // var a =[1,2,3,1,2,8]
    // console.log(...a);//1 2 3 1 2 8

    // 多维数组
    // var a = [[1, 5,],[8, 32, 3], [9, 4, 5]]
    // // 合并数组
    // var a = [...[1, 5], ...[8, 32, 3], ...[9, 4, 5]]
    // console.log(a);

    // 可以把伪数组转换为数组
    // function fn() {
    //     console.log([...arguments]);
    // }
    // fn(1, 2, 55, 3, 6, 1)

    // 传多个值
    // function fn(a, b, c, d) {
    //     console.log(a, b, c, d);
    // }
    // fn(1, 2, 3, 4, 5, 6, 7, 8, 9)//1 2 3 4
    // fn(...[1, 2, 3, 4, 5, 6, 7, 8, 9])//函数参数展开传入

    // var a =[1,2,3,1,2,8]
    // // 浅拷贝
    // console.log(...[a]);

    // ===============================================================================
    // 对象
    // 扩展运算符
    // var data = {
    //     name: 'jay',
    //     age: '18',
    //     hobby: {
    //         one: 'music',
    //         two: 'xx',
    //         three: ['a', 'b']
    //     },
    //     sex: ['man', 'women', { other: 'gay' }]
    // }
    // var b = { ...data }
    // var c = { ...data.hobby }
    // var d = { ...data.sex }
    // console.log(b,c,d);





    // ===============================================================================
    // 静态方法和实例方法
    // -------------------------------------------------------------------------
    // 静态方法是可以用实例直接调用的

    // 数组
    // Array的静态方法：（类名可以直接调用）
    // Array.from()    Array.of()

    // Array.from()
    // 可以将类似数组的对象转换为数组
    // console.log(Array.from({ length: 10 }));

    // Array.of()
    // 里面的参数都是数组的元素，不论个数
    // console.log(Array.of(1, 2, 3, 4, 5, 6, 7));

    // new Arrary() 一个参数代表长度，两个参数以上为数组元素
    // console.log(new Array(5));//length:5
    // console.log(new Array(1, 2, 3, 4));


    // -------------------------------------------------------------------------
    // 实例方法
    // 数组
    // Array的实例方法：（只有实例才能调用）
    // find、findIdex     fill     keys/values/entries    flat   includes   at
    // var a = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 8]


    // // find、findIdex（返回符合要求的第一个元素/索引）
    // var b = a.find(v => v > 5)
    // console.log(b);//元素8
    // var b = a.findIndex(v => v > 5)
    // console.log(b);//索引10






    // // fill 填充(给数组填充指定数组)
    // var b = a.fill('2')
    // console.log(b);
    // // 第一个参数是要填充的元素，第二个参数代表开始的位置，第三个参数代表结束位置
    // // 不包含结束位置
    // var b = a.fill('2', 2, 5)
    // console.log(b);




    // keys把数组的索引取出来放进新的数组
    // values:把数组的元素取出来放入新的数组
    // entries：把数组和索引抽出来放进二维数组中






    // // flat  拍平数组
    // // 把嵌套的多维数组，变成一维数组
    // var a = [123, 2312, [13122, 153213, [12, 2, [45, 12, 96, 15, [12, 78, [41]]]]]]
    // console.log(a.flat(Infinity));//Infinity无穷的
    // // 先把多维数组变成字符串使用','隔开，再将字符串变成数组也可以实现拍平多维数组
    // a = a.join(',')
    // a = a.split(',')
    // console.log(a);
    // 使用递归找元素
    // function fn() {
    //     a.forEach(item => {
    //         if (Array.isArray(item)) {
    //             fn(item)
    //         } else {
    //           //找元素
    //         }
    //     })
    // }
    // fn()



    // // includes
    // // 返回布尔值，如果数组包含给定的值，返回true否则为false
    // var a = [1, 2, 4, 5, 2, 3, 4, 2, 1, 5, 2,];
    // console.log(a.includes(8));//false
    // console.log(a.includes(2));//true
    // // 第二个参数代表的查询的开始位置
    // console.log(a.includes(8,2));//false
    // console.log(a.includes(4,2));//true





    // // at
    // // 接受一个整数作为参数，返回对应的位置，支持负索引（数组，字符串，类型数组都可以使用）
    // // 数组
    // var a =[1,2,5,3,6,4]
    // console.log(a.at(0));//1
    // console.log(a.at(-1));//4
    // // 字符串
    // var a = 'jay hello love you'
    // console.log(a.at(0));//j
    // console.log(a.at(-1));//u
    // // 如果超出返回undefined
    // console.log(a.at(100));
    // console.log(a.at(-100));


    // // 数组的四个扩展方法（不改变原数组）
    // // toReversed()，toSorted()，toSpliced()，with()
    // var a = [8, 2, 6, 4, 5, 2, 1]
    // // 截取
    // console.log(a.toSpliced(1, 2, 0));
    // // 颠倒数组
    // console.log(a.toReversed());





    // // reduce
    // // 第一个参数为回调函数（迭代器），第二个参数为初始值
    // // 第一个参数里的回调函数参数分别是：
    // //      1.total ：每次迭代返回的结果，第一次就是初始值,如果第二个参数没有传，
    // //                那么total的初始值就是第一次迭代的返回值。
    // //      2.currentValue：每次迭代的当前元素
    // //      3.currentIndex：每次迭代的当前索引
    // //      4.array：原数组
    // // 求a数组中所有元素的和
    // var a = [1, 2, 3, 4, 5, 6];
    // var b = a.reduce((total, current, index, array) => {
    //     total = total + current;
    //     return total;
    // }, 0)
    // console.log(b);//21


    // 面试题：统计字符串中每个字母出现的次数
    // var a = 'sssssssssssssssssssssssssssssssssssssok'
    // lih/////////////////////S
    // var var splic = a = split(''), reduce('
    // ');


</script>

</html>